package v2ray

import (
	"errors"
	"gitee.com/Luna-CY/hui-hui/internal/interface/application"
	"gitee.com/Luna-CY/hui-hui/internal/util/data"
	"gitee.com/Luna-CY/hui-hui/internal/util/point"
	"github.com/google/uuid"
)

// NewVMessInbound 创建VMess入站协议
func NewVMessInbound(id string, tag string, listen string, gport int, disableInsecureEncryption bool, clients []*application.V2rayVMessClient, stream *application.V2rayStreamSettings) (*application.V2rayBound, error) {
	if "" == listen || 0 == gport {
		return nil, errors.New("入栈协议必须提供监听的本地地址与端口")
	}

	if 0 == len(clients) {
		return nil, errors.New("VMess入站协议必须提供至少一个客户端配置")
	}

	var bound = &application.V2rayBound{Id: id, Tag: tag, Protocol: application.V2rayBoundProtocolVMess}
	bound.Inbound.Listen = listen
	bound.Inbound.Port = gport

	if "" == bound.Id {
		bound.Id = uuid.New().String()
	}

	bound.VMess.Inbound.DisableInsecureEncryption = disableInsecureEncryption
	bound.VMess.Inbound.Clients = clients

	if err := SetBoundStreamSettings(bound, stream); nil != err {
		return nil, err
	}

	return bound, nil
}

// NewVMessOutbound 创建VMess出站协议
func NewVMessOutbound(id string, tag string, sendThrough string, vNextList []*application.V2rayVMessVnext, stream *application.V2rayStreamSettings) (*application.V2rayBound, error) {
	if 0 == len(vNextList) {
		return nil, errors.New("VMess的出站协议配置需要至少一个VNext配置")
	}

	var bound = &application.V2rayBound{Id: id, Tag: tag, Protocol: application.V2rayBoundProtocolVMess}

	bound.Outbound.SendThrough = sendThrough
	if "" == bound.Outbound.SendThrough {
		bound.Outbound.SendThrough = "0.0.0.0"
	}

	if "" == bound.Id {
		bound.Id = uuid.New().String()
	}

	bound.VMess.Outbound.Vnext = vNextList

	if err := SetBoundStreamSettings(bound, stream); nil != err {
		return nil, err
	}

	return bound, nil
}

// NewFreedomOutbound 创建Freedom出站协议
func NewFreedomOutbound(id string, tag string, sendThrough string, domainStrategy application.V2rayFreedomDomainStrategy, redirect string, userLevel int, stream *application.V2rayStreamSettings) (*application.V2rayBound, error) {
	var bound = &application.V2rayBound{Id: id, Tag: tag, Protocol: application.V2rayBoundProtocolFreedom}

	bound.Outbound.SendThrough = sendThrough
	if "" == bound.Outbound.SendThrough {
		bound.Outbound.SendThrough = "0.0.0.0"
	}

	if "" == bound.Id {
		bound.Id = uuid.New().String()
	}

	bound.Freedom.DomainStrategy = domainStrategy
	bound.Freedom.Redirect = redirect
	bound.Freedom.UserLevel = userLevel

	if err := SetBoundStreamSettings(bound, stream); nil != err {
		return nil, err
	}

	return bound, nil
}

// SetBoundStreamSettings 设置入站/出站协议的传输配置项
// 该方法将传入的传输配置转换为有效的传输配置结构，并设置到入站/出站协议对象
func SetBoundStreamSettings(bound *application.V2rayBound, stream *application.V2rayStreamSettings) error {
	if nil == stream {
		return errors.New("缺少底层传输配置")
	}

	bound.StreamSettings.Enable = stream.Enable
	bound.StreamSettings.Network = stream.Network

	bound.StreamSettings.TlsSettings.ClientOnly = stream.TlsSettings.ClientOnly
	bound.StreamSettings.TlsSettings.Security = data.Default(stream.TlsSettings.Security, "none")
	bound.StreamSettings.TlsSettings.ServerName = stream.TlsSettings.ServerName
	if "none" != stream.TlsSettings.Security && "tls" != stream.TlsSettings.Security {
		return errors.New("TLS安全类型错误，只能为none或tls")
	}

	// tcp
	bound.StreamSettings.TcpSettings.Header.Type = data.Default(stream.TcpSettings.Header.Type, "none")

	// kcp
	bound.StreamSettings.KcpSettings.Mtu = data.Default(stream.KcpSettings.Mtu, 1350)
	if !data.CheckNumberRange(bound.StreamSettings.KcpSettings.Mtu, 576, 1460) {
		return errors.New("KCP的MTU配置大小无效，MTU必须在576-1460之间")
	}

	bound.StreamSettings.KcpSettings.Tti = data.Default(stream.KcpSettings.Tti, 50)
	if !data.CheckNumberRange(bound.StreamSettings.KcpSettings.Tti, 1, 100) {
		return errors.New("KCP的TTI配置大小无效，TTI必须在1-100之间")
	}

	bound.StreamSettings.KcpSettings.UplinkCapacity = data.Default(stream.KcpSettings.UplinkCapacity, point.New(5))
	bound.StreamSettings.KcpSettings.DownlinkCapacity = data.Default(stream.KcpSettings.DownlinkCapacity, point.New(5))
	bound.StreamSettings.KcpSettings.ReadBufferSize = data.Default(stream.KcpSettings.ReadBufferSize, 2)
	bound.StreamSettings.KcpSettings.WriteBufferSize = data.Default(stream.KcpSettings.WriteBufferSize, 2)
	bound.StreamSettings.KcpSettings.Congestion = stream.KcpSettings.Congestion
	bound.StreamSettings.KcpSettings.Header.Type = data.Default(stream.KcpSettings.Header.Type, "none")

	// websocket
	bound.StreamSettings.WebsocketSettings.Path = data.Default(stream.WebsocketSettings.Path, "/")
	bound.StreamSettings.WebsocketSettings.Headers = stream.WebsocketSettings.Headers

	// domain socket
	bound.StreamSettings.DomainSocketSettings.Path = stream.DomainSocketSettings.Path

	// http
	bound.StreamSettings.Http2Settings.Host = stream.Http2Settings.Host
	bound.StreamSettings.Http2Settings.Path = data.Default(stream.Http2Settings.Path, "/")

	// quic
	bound.StreamSettings.QuicSettings.Security = data.Default(stream.QuicSettings.Security, "none")
	bound.StreamSettings.QuicSettings.Key = stream.QuicSettings.Key
	bound.StreamSettings.QuicSettings.Header.Type = data.Default(stream.QuicSettings.Header.Type, "none")

	return nil
}
